package cn.xiyun.xiyuncc.service.impl;

import cn.xiyun.xiyuncc.domain.MessageSms;
import cn.xiyun.xiyuncc.domain.SmsBlocking;
import cn.xiyun.xiyuncc.domain.User;
import cn.xiyun.xiyuncc.dto.SmsCodeDto;
import cn.xiyun.xiyuncc.exception.OperationException;
import cn.xiyun.xiyuncc.feignClient.UserFeignClient;
import cn.xiyun.xiyuncc.mapper.MessageSmsMapper;
import cn.xiyun.xiyuncc.mapper.SmsBlockingMapper;
import cn.xiyun.xiyuncc.result.JSONResult;
import cn.xiyun.xiyuncc.service.ISmsBlockingService;
import cn.xiyun.xiyuncc.service.IVerifycodeService;
import cn.xiyun.xiyuncc.util.VerifyCodeUtils;
import org.aspectj.weaver.ast.Var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class VerifycodeServiceImpl implements IVerifycodeService {
    /**
     * IP地址拉黑KEY
     */
    private static final String IP_KEY = "IP_ADDRESS_MASKING";
    /**
     * 电话号码拉黑KEY
     */
    private static final String PHONE_KEY = "PHONE_NUMBER_BLOCKING";

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private MessageSmsMapper messageSmsMapper;
    @Autowired
    private ISmsBlockingService smsBlockingService;


    /**
     * 图形验证码
     *
     * @param imageCodeKey
     * @return
     */
    @Override
    public String imageCode(String imageCodeKey) {
        // 生成随机数字长度4
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        System.out.println(verifyCode);
        // 生成图形验证码
        String code = VerifyCodeUtils.verifyCode(70, 30, verifyCode);
        // 存入redis key:uuid values:随机数字 600秒
        redisTemplate.opsForValue().set(imageCodeKey, verifyCode, 600, TimeUnit.SECONDS);
        return code;
    }

    /**
     * 电话号码拉黑
     *
     * @param ip
     * @param phone
     */
    public boolean phoneBlocking(String ip, String phone) {
        //时间戳获取
        Long l = System.currentTimeMillis();
        String timeMilli = l.toString();

        // 电话拉黑
        //从redis获取
        String phoneKey = phone + ":" + PHONE_KEY;
        String phoneValue = (String) redisTemplate.opsForValue().get(phoneKey);
        //判断是否为空
        if (phoneValue == null) {
            phoneValue = timeMilli + ":" + phone + ":1";
            // 空则拼接字符串放入redis
            redisTemplate.opsForValue().set(phoneKey, phoneValue, 5, TimeUnit.MINUTES);
            return true;
        } else {
            // 获取短信发送次数
            String phoneCode = phoneValue.split(":")[2];
            Integer phoneCodeInteger = Integer.valueOf(phoneCode);

            // 小于拉黑策略则次数+1
            if (phoneCodeInteger <= 3) {
                // 次数+1
                phoneCodeInteger = phoneCodeInteger + 1;
                // 拼接字符串
                phoneValue = timeMilli + ":" + phone + ":" + phoneCodeInteger;
                // 放入redis
                redisTemplate.opsForValue().set(phoneKey, phoneValue, 120, TimeUnit.MINUTES);
                return true;
            } else {
                // 存入拉黑数据库记录信息
                if (phoneCodeInteger == 4) {
                    SmsBlocking smsBlocking = new SmsBlocking();
                    smsBlocking.setPhone(phone);
                    smsBlocking.setIp(ip);
                    smsBlocking.setCreationTime(new Date());
                    smsBlockingService.insert(smsBlocking);
                    // 大于拉黑策略则放入redis并存入数据库记录,存入redis拉黑两个小时
                    // 次数+1
                    phoneCodeInteger = phoneCodeInteger + 1;
                    // 拼接字符串
                    phoneValue = timeMilli + ":" + phone + ":" + phoneCodeInteger;
                    redisTemplate.opsForValue().set(phoneKey, phoneValue, 120, TimeUnit.MINUTES);
                }
                //throw new OperationException("频繁获取短信电话号码已拉黑,请在两小时后重试");
                return false;
            }
        }
    }

    /**
     * IP地址拉黑
     * @param ip
     * @param phone
     * @return
     */
    public boolean ipBlocking(String ip, String phone) {
        //时间戳获取
        Long l = System.currentTimeMillis();
        String timeMilli = l.toString();
        // IP地址拉黑
        // redis获取ip信息
        String ipKey = ip + ":" + IP_KEY;
        String ipValue = (String) redisTemplate.opsForValue().get(ipKey);

        //判断是否为空
        if (ipValue == null) {
            ipValue = timeMilli + ":" + ip + ":1";
            // 空则拼接字符串放入redis
            redisTemplate.opsForValue().set(ipKey, ipValue, 5, TimeUnit.MINUTES);
            return true;
        } else {
            // 获取短信发送次数
            String ipCode = ipValue.split(":")[2];
            Integer ipCodeInteger = Integer.valueOf(ipCode);
            // 小于拉黑策略则次数+1
            if (ipCodeInteger <= 3) {
                // 次数+1
                ipCodeInteger = ipCodeInteger + 1;
                // 拼接字符串
                ipValue = timeMilli + ":" + ip + ":" + ipCodeInteger;
                // 放入redis
                redisTemplate.opsForValue().set(ipKey, ipValue, 120, TimeUnit.MINUTES);
                return true;
            } else {
                // 大于拉黑策略则放入redis并存入数据库记录,存入redis拉黑两个小时
                if (ipCodeInteger == 4) {
                    SmsBlocking smsBlocking = new SmsBlocking();
                    smsBlocking.setPhone(phone);
                    smsBlocking.setIp(ip);
                    smsBlocking.setCreationTime(new Date());
                    smsBlockingService.insert(smsBlocking);
                    // 次数+1
                    ipCodeInteger = ipCodeInteger + 1;
                    // 拼接字符串
                    ipValue = timeMilli + ":" + ip + ":" + ipCodeInteger;
                    redisTemplate.opsForValue().set(ipKey, ipValue, 120, TimeUnit.MINUTES);
                }
                //throw new OperationException("频繁获取短信ip地址已拉黑,请在两小时后重试");
                return false;
            }
        }
    }

    /**
     * 短信验证码
     *
     * @param smsCodeDto
     * @return
     * @throws Exception
     */
    @Override
    public JSONResult sendSmsCode(SmsCodeDto smsCodeDto) throws Exception {
        // UUID
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        // 图形验证码
        String imageCode = smsCodeDto.getImageCode();
        // 手机号
        String mobile = smsCodeDto.getMobile();
        // IP地址
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String ip = requestAttributes.getRequest().getRemoteAddr();
        //判断是否注册
        User user = userFeignClient.phoneToUser(mobile);
        if (user != null) {
            throw new OperationException("用户已注册请直接登录", "USER_REGISTERED_PLEASE_LOGIN_DIRECTLY");
        }
        // 通过 uuid 获取图形验证码
        String value = (String) redisTemplate.opsForValue().get(imageCodeKey);
        System.out.println(value);
        // 判断图形验证码是否过期
        if (value == null) {
            throw new OperationException("图形验证码过期", "VERIFICATION_CODE_EXPIRED_265269549");
        }
        // 判断图形验证码是否正确
        if (!imageCode.equals(value)) {
            throw new OperationException("图形验证码错误", "VERIFICATION_CODE_EXCEPTION_15641651465");
        }
        /**
         // 获取验证码(2)
         //通过电话号码获得验证信息
         String st1 = (String) redisTemplate.opsForValue().get(mobile);
         if(st1!=null){
         String codeTime = st1.split(":")[1];//验证码的时间戳
         long nowTime = Long.parseLong(codeTime);
         long time = new Date().getTime();
         if (nowTime-time>1000*60*3){
         throw new OperationException("短时间不可重复获取短信验证码", "repeated_acquisition_26546465");
         }

         }else {
         // 生成随机字符串
         String verifyCode = VerifyCodeUtils.generateVerifyCode(6, new String("1234567890"));
         // 时间戳
         long time = System.currentTimeMillis();
         //拼接字符串
         String reValue = verifyCode+":"+time;
         // 存入redis key:mobile values:随机数字300秒/5分钟(防止重复发送)
         redisTemplate.opsForValue().set(mobile, reValue, 300, TimeUnit.SECONDS);
         }

         */
        // 通过电话号码判断是否短时间内重复发送验证码
        String codeKey = mobile + ":" + imageCodeKey;
        String st = (String) redisTemplate.opsForValue().get(codeKey);
        /*if (st != null) {
            throw new OperationException("短时间不可重复获取短信验证码", "REPEATED_ACQUISITION_26546465");
        }*/

        boolean phoneBlock = phoneBlocking(ip, mobile);
        if (!phoneBlock){
            return new JSONResult().error("频繁获取短信验证码电话号码已拉黑,请在两小时后重试");
        }
        boolean ipBlock = ipBlocking(ip, mobile);
        if (!ipBlock){
            return new JSONResult().error("频繁获取短信验证码IP地址已拉黑,请在两小时后重试");
        }

        // 生成随机字符串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(6, new String("1234567890"));
        //将数据存入redis
        // 存入redis key:mobile values:随机数字60秒/1分钟(防止重复发送)
        redisTemplate.opsForValue().set(codeKey, verifyCode, 60, TimeUnit.SECONDS);
        // 存入redis key:uuid values:随机数字 300秒/5分钟()
        redisTemplate.opsForValue().set(mobile, verifyCode, 300, TimeUnit.SECONDS);
        //短信发送
        String smsMessage = new String("析云课堂:您的短信验证码为<h1>" + verifyCode + "</h1>5分钟内有效");
        // 存储到短信发送记录
        MessageSms messageSms = new MessageSms();
        messageSms.setPhone(mobile);
        messageSms.setContent(smsMessage);
        messageSms.setTitle(new String("用户注册"));
        messageSms.setSendTime(new Date());
        messageSms.setIp(ip);
        messageSmsMapper.insert(messageSms);
        /** SmsUtil smsUtil = new SmsUtil();
         smsUtil.smsMassage(mobile,smsMessage);*/
        System.out.println(new String("析云课堂:您的短信验证码为<h1>" + verifyCode + "</h1>10分钟内有效"));
        return new JSONResult();
    }


}
